package com.apop.hrss.jwt;

import com.apop.common.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.jose4j.json.JsonUtil;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.NumericDate;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.lang.JoseException;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;


@Slf4j
public class JWTInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求头中令牌
        String token = request.getHeader("pz_token");
        // 如果是h5登陆
        if (StringUtils.isEmpty(token)) {
            token = request.getHeader("h5_token");
        }

        if (StringUtils.isEmpty(token)){
            throw new BizException("E501","token为空");
        }

        try {
            String result = verifyToken(token); // 如果找到令牌就使用 JWTUtils.parseJwt() 方法解析令牌
            if (result == null){

            }
            log.info("认证通过 {} ", result);
            return true;                                     // 解析成功，即令牌有效，返回true
        }
        catch (JoseException je){
            throw new BizException("E501","token校验失败!"+je.getMessage());
        }
        catch (InvalidJwtException ije){
            /**
             * iat（Issued At）作用：表示JWT的发行时间。即令牌被创建和签发的时间点。
             * exp 表示JWT的过期时间。即令牌在何时失效，不再被接受为有效认证。
             *
             */
            JwtClaims jwtClaims = ije.getJwtContext().getJwtClaims();
            NumericDate numericDate = jwtClaims.getExpirationTime();
            // 将时间戳转换为Instant对象
            Instant instant = Instant.ofEpochSecond(numericDate.getValue());
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
            // 格式化输出日期和时间
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            log.error("token 失效时间: {} ",localDateTime.format(formatter));

            throw new BizException("E502","token已经失效 过期时间是 "+localDateTime.format(formatter));
        }
        catch (RuntimeException e) {
            e.printStackTrace();
            throw new BizException("E501","token校验失败!");
        }

    }

    private static String publicKeyStr = "{\"kty\":\"RSA\",\"kid\":\"fa677d525c0e4ee485a61543937794af\",\"alg\":\"RS256\",\"n\":\"ki6NKW2ow53FBjWf21xNGF0v-Fzv9R4-vu5tz7LHz4vZ7TE2Lp7Xx0N2vFIH-HLZPLfAYW35W5iV29sW_MkbhVlh6f0q4AeCIeYrVjBGbcYTK5g-Sb8i9sO78DkGivryKTU4tUnOjqar2bfobwXScFhAgc4-BjIcvZ9V8LEzcAW76he500-sqekXqvYv7LbxIMlbadGEwbBqjscE83hiYjk1KSFrEeNWKP6E0X_cHVGEEGys8IKlBcfwOOCgaJ0sCFxvN3M54V33jSUknFzHAi1qJRsOI87-Fk1oYS-aniQOTfm5y5x1syTIgWEX9JvXCQgTxjp2kMItuoL2G2faoQ\",\"e\":\"AQAB\"}";

    /**
     * jws校验token
     *
     * @param token
     * @return 返回 用户账号
     * @throws JoseException
     */
    public String verifyToken(String token) throws InvalidJwtException, JoseException {
        try {

            JwtConsumer consumer = new JwtConsumerBuilder()
                    .setRequireExpirationTime()
                    .setMaxFutureValidityInMinutes(5256000)
                    .setAllowedClockSkewInSeconds(30)
                    .setRequireSubject()
                    //.setExpectedIssuer("")
                    .setExpectedAudience("YOUR_AUDIENCE")
                    /*
                    RsaJsonWebKey jwk = null;
                    try {
                        jwk = RsaJwkGenerator.generateJwk(2048);
                        } catch (JoseException e) {
                            e.printStackTrace();
                        }
                        jwk.setKeyId(keyId); */
                    //.setVerificationKey(jwk.getPublicKey())
                    .setVerificationKey(new RsaJsonWebKey(JsonUtil.parseJson(publicKeyStr)).getPublicKey())
                    .build();

            JwtClaims claims = consumer.processToClaims(token);
            String account = claims.getClaimValue("account", String.class);
            NumericDate expirationTime = claims.getExpirationTime();
            log.info("Token is valid. Payload custom content: user account=" + account);
            log.info("Token expiration time: " + expirationTime.getValue());

            // 将时间戳转换为Instant对象
            Instant instant = Instant.ofEpochSecond(expirationTime.getValue());
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
            // 格式化输出日期和时间
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            log.error("token 失效时间: {} ",localDateTime.format(formatter));


            return account;
        }  catch (JoseException e) {
            e.printStackTrace();
            throw e;
        }  catch (InvalidJwtException e) {
            // 如果上面的方法不存在，你可以打印一个通用的超期消息
            log.error("JWT has expired. Unable to process the token.");
            e.printStackTrace();
            throw e;
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
